package com.roundarch.flex.controls.graphControlConstraints
{
    import com.roundarch.flex.controls.graphControlInterfaces.IGraphControlSelector;
    import flash.events.Event;
    import flash.events.EventDispatcher;
    import flash.geom.Point;

    /**
     *
     * @author jjung
     */
    public class ConstraintRelative extends EventDispatcher implements ISelectorConstraint
    {
        //---------------------------------------------------------------------
        //
        //  Variables
        //
        //---------------------------------------------------------------------
        /**
         * This is to keep us from avoiding a dependency deadlock on the constraint.
         */
        private var constraintRunning : Boolean = false;

        //---------------------------------------------------------------------
        //
        //  Properties
        //
        //---------------------------------------------------------------------
        //-----------------------------
        // direction
        //-----------------------------
        /**
         * @private
         */
        protected var _direction : String = "horizontal";

        [Bindable("directionChanged")]
        /**
         *
         *
         * @default "horizontal"
         */
        public function get direction() : String
        {
            return _direction;
        }

        /**
         * @private
         */
        public function set direction(value : String) : void
        {
            if (value == _direction)
            {
                return;
            }

            _direction = value;

            dispatchEvent(new Event("directionChanged"));
        }

        //-----------------------------
        // minDistance
        //-----------------------------
        /**
         * @private
         */
        protected var _minDistance : Number = 1;

        [Bindable("minDistanceChanged")]
        /**
         *
         *
         * @default null
         */
        public function get minDistance() : Number
        {
            return _minDistance;
        }

        /**
         * @private
         */
        public function set minDistance(value : Number) : void
        {
            if (value == _minDistance)
            {
                return;
            }

            _minDistance = value;

            dispatchEvent(new Event("minDistanceChanged"));
        }

        //-----------------------------
        // selector1
        //-----------------------------
        /**
         * @private
         */
        protected var _selector1 : IGraphControlSelector = null;

        [Bindable("selector1Changed")]
        /**
         *
         *
         * @default null
         */
        public function get selector1() : IGraphControlSelector
        {
            return _selector1;
        }

        /**
         * @private
         */
        public function set selector1(value : IGraphControlSelector) : void
        {
            if (value == _selector1)
            {
                return;
            }

            _selector1 = value;

            dispatchEvent(new Event("selector1Changed"));
        }

        //-----------------------------
        // selector2
        //-----------------------------
        /**
         * @private
         */
        protected var _selector2 : IGraphControlSelector = null;

        [Bindable("selector2Changed")]
        /**
         *
         *
         * @default null
         */
        public function get selector2() : IGraphControlSelector
        {
            return _selector2;
        }

        /**
         * @private
         */
        public function set selector2(value : IGraphControlSelector) : void
        {
            if (value == _selector2)
            {
                return;
            }

            _selector2 = value;

            dispatchEvent(new Event("selector2Changed"));
        }

        //---------------------------------------------------------------------
        //
        //  Constructor
        //
        //---------------------------------------------------------------------
        /**
         *  Constructor
         */
        public function ConstraintRelative()
        {
        }

        //---------------------------------------------------------------------
        //
        //  Methods
        //
        //---------------------------------------------------------------------
        /**
         * This checks to see whether the new point provided when applied to selector1 will cause
         * selector1 to collied with selector2. If so, the methods attempts to move selector2 relative
         * to the new position of selector1. If that was successful, we return the new position of selector1.
         */
        public function constrain(requestedPoint : Point, selector : IGraphControlSelector) : Point
        {
            if (constraintRunning)
            {
                return requestedPoint;
            }

            constraintRunning = true;

            if (selector1 && selector2 && selector1.value && selector2.value)
            {
                if (direction == "horizontal" && selector == selector1)
                {
                    var dis : Number = selector2.value.x - requestedPoint.x;
                    var delta : Number = minDistance - dis;

                    // We need to move selector2 to the right.
                    if (delta > 0)
                    {
                        var oldSel2 : Point = new Point(selector2.value.x, selector2.value.y);

                        selector2.invalidateValue(new Point(selector2.value.x + delta, selector2.value.y));

                        requestedPoint.x = selector2.value.x - minDistance;
                    }
                }
                else if (direction == "horizontal" && selector == selector2)
                {
                    var dis : Number = requestedPoint.x - selector1.value.x;
                    var delta : Number = minDistance - dis;

                    // We need to move selector2 to the right.
                    if (delta > 0)
                    {
                        var oldSel1 : Point = new Point(selector1.value.x, selector1.value.y);

                        selector1.invalidateValue(new Point(selector1.value.x - delta, selector1.value.y));

                        requestedPoint.x = selector1.value.x + minDistance;
                    }
                }
            }

            constraintRunning = false;

            return requestedPoint;
        }
    }
}
